diff options
author | Douglas Gregor <dgregor@apple.com> | 2010-04-18 07:40:54 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2010-04-18 07:40:54 +0000 |
commit | 523d46af407f32fc53861e6f068e8076d4fe84a8 (patch) | |
tree | b3b5b25735fde4b6b4ae54b2b61a9454aa8aaaf3 /lib/Sema/SemaInit.cpp | |
parent | 389980e3602820768714ef2123cb466db3e0d301 (diff) |
In C++98/03, when binding a reference to an rvalue of
reference-compatible type, the implementation is permitted to make a
copy of the rvalue (or many such copies, even). However, even though
we don't make that copy, we are required to check for the presence of
a suitable copy constructor. With this change, we do.
Note that in C++0x we are not allowed to make these copies, so we test
both dialects separately.
Also note the FIXME in one of the C++03 tests, where we are not
instantiating default function arguments for the copy constructor we
pick (but do not call). The fix is obvious; eliminating the infinite
recursion it causes is not. Will address that next.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@101704 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaInit.cpp')
-rw-r--r-- | lib/Sema/SemaInit.cpp | 86 |
1 files changed, 73 insertions, 13 deletions
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index db7c1b396a..59f4393e55 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -1987,6 +1987,7 @@ void InitializationSequence::Step::Destroy() { case SK_CastDerivedToBaseLValue: case SK_BindReference: case SK_BindReferenceToTemporary: + case SK_ExtraneousCopyToTemporary: case SK_UserConversion: case SK_QualificationConversionRValue: case SK_QualificationConversionLValue: @@ -2067,6 +2068,13 @@ void InitializationSequence::AddReferenceBindingStep(QualType T, Steps.push_back(S); } +void InitializationSequence::AddExtraneousCopyToTemporary(QualType T) { + Step S; + S.Kind = SK_ExtraneousCopyToTemporary; + S.Type = T; + Steps.push_back(S); +} + void InitializationSequence::AddUserConversionStep(FunctionDecl *Function, DeclAccessPair FoundDecl, QualType T) { @@ -2483,6 +2491,18 @@ static void TryReferenceInitialization(Sema &S, // reference-compatible with "cv2 T2", or if (InitLvalue != Expr::LV_Valid && RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { + // The corresponding bullet in C++03 [dcl.init.ref]p5 gives the + // compiler the freedom to perform a copy here or bind to the + // object, while C++0x requires that we bind directly to the + // object. Hence, we always bind to the object without making an + // extra copy. However, in C++03 requires that we check for the + // presence of a suitable copy constructor: + // + // The constructor that would be used to make the copy shall + // be callable whether or not the copy is actually done. + if (!S.getLangOptions().CPlusPlus0x) + Sequence.AddExtraneousCopyToTemporary(cv2T2); + if (DerivedToBase) Sequence.AddDerivedToBaseCastStep( S.Context.getQualifiedType(T1, T2Quals), @@ -3108,15 +3128,35 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) { llvm_unreachable("missed an InitializedEntity kind?"); } +/// \brief Make a (potentially elidable) temporary copy of the object +/// provided by the given initializer by calling the appropriate copy +/// constructor. +/// +/// \param S The Sema object used for type-checking. +/// +/// \param T The type of the temporary object, which must either by +/// the type of the initializer expression or a superclass thereof. +/// +/// \param Enter The entity being initialized. +/// +/// \param CurInit The initializer expression. +/// +/// \param IsExtraneousCopy Whether this is an "extraneous" copy that +/// is permitted in C++03 (but not C++0x) when binding a reference to +/// an rvalue. +/// +/// \returns An expression that copies the initializer expression into +/// a temporary object, or an error expression if a copy could not be +/// created. static Sema::OwningExprResult CopyObject(Sema &S, + QualType T, const InitializedEntity &Entity, - const InitializationKind &Kind, - Sema::OwningExprResult CurInit) { + Sema::OwningExprResult CurInit, + bool IsExtraneousCopy) { // Determine which class type we're copying to. Expr *CurInitExpr = (Expr *)CurInit.get(); CXXRecordDecl *Class = 0; - if (const RecordType *Record - = Entity.getType().getNonReferenceType()->getAs<RecordType>()) + if (const RecordType *Record = T->getAs<RecordType>()) Class = cast<CXXRecordDecl>(Record->getDecl()); if (!Class) return move(CurInit); @@ -3137,7 +3177,7 @@ static Sema::OwningExprResult CopyObject(Sema &S, // not yet) handled as part of constructor initialization, while // copy elision for exception handlers is handled by the run-time. bool Elidable = CurInitExpr->isTemporaryObject() && - S.Context.hasSameUnqualifiedType(Entity.getType(), CurInitExpr->getType()); + S.Context.hasSameUnqualifiedType(T, CurInitExpr->getType()); SourceLocation Loc; switch (Entity.getKind()) { case InitializedEntity::EK_Result: @@ -3217,9 +3257,23 @@ static Sema::OwningExprResult CopyObject(Sema &S, CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Best->Function); ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S); CurInit.release(); // Ownership transferred into MultiExprArg, below. + + S.CheckConstructorAccess(Loc, Constructor, + Best->FoundDecl.getAccess()); + + if (IsExtraneousCopy) { + // If this is a totally extraneous copy for C++03 reference + // binding purposes, just return the original initialization + // expression. + + // FIXME: We'd like to call CompleteConstructorCall below, so that + // we instantiate default arguments and such. + return S.Owned(CurInitExpr); + } // Determine the arguments required to actually perform the - // constructor call (we might have derived-to-base conversions). + // constructor call (we might have derived-to-base conversions, or + // the copy constructor may have default arguments). if (S.CompleteConstructorCall(Constructor, Sema::MultiExprArg(S, (void **)&CurInitExpr, @@ -3227,12 +3281,7 @@ static Sema::OwningExprResult CopyObject(Sema &S, Loc, ConstructorArgs)) return S.ExprError(); - S.CheckConstructorAccess(Loc, Constructor, - Best->FoundDecl.getAccess()); - - return S.BuildCXXConstructExpr(Loc, Entity.getType().getNonReferenceType(), - Constructor, - Elidable, + return S.BuildCXXConstructExpr(Loc, T, Constructor, Elidable, move_arg(ConstructorArgs)); } @@ -3326,6 +3375,7 @@ InitializationSequence::Perform(Sema &S, case SK_CastDerivedToBaseLValue: case SK_BindReference: case SK_BindReferenceToTemporary: + case SK_ExtraneousCopyToTemporary: case SK_UserConversion: case SK_QualificationConversionLValue: case SK_QualificationConversionRValue: @@ -3421,6 +3471,11 @@ InitializationSequence::Perform(Sema &S, break; + case SK_ExtraneousCopyToTemporary: + CurInit = CopyObject(S, Step->Type, Entity, move(CurInit), + /*IsExtraneousCopy=*/true); + break; + case SK_UserConversion: { // We have a user-defined conversion that invokes either a constructor // or a conversion function. @@ -3497,7 +3552,8 @@ InitializationSequence::Perform(Sema &S, IsLvalue)); if (RequiresCopy) - CurInit = CopyObject(S, Entity, Kind, move(CurInit)); + CurInit = CopyObject(S, Entity.getType().getNonReferenceType(), Entity, + move(CurInit), /*IsExtraneousCopy=*/false); break; } @@ -4040,6 +4096,10 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const { OS << "bind reference to a temporary"; break; + case SK_ExtraneousCopyToTemporary: + OS << "extraneous C++03 copy to temporary"; + break; + case SK_UserConversion: OS << "user-defined conversion via " << S->Function.Function; break; |