From 9556257252cec8531730f8c76263293723a7defd Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Sat, 24 Apr 2010 23:45:46 +0000 Subject: [PATCH] When we create a temporary of class type that we don't immediately bind, check accessibility of the destructor and mark the declaration as referenced. Fixes a bunch of Boost.Regex failures. llvm-svn: 102287 --- clang/lib/Sema/SemaInit.cpp | 51 +++++++++++++++++++++++++++--- clang/test/CXX/class.access/p4.cpp | 13 ++++++++ 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index ea430bbd3ebe..e1269a7e1297 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -3138,6 +3138,8 @@ getAssignmentAction(const InitializedEntity &Entity) { return Sema::AA_Converting; } +/// \brief Whether we should binding a created object as a temporary when +/// initializing the given entity. static bool shouldBindAsTemporary(const InitializedEntity &Entity) { switch (Entity.getKind()) { case InitializedEntity::EK_ArrayElement: @@ -3158,6 +3160,28 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) { llvm_unreachable("missed an InitializedEntity kind?"); } +/// \brief Whether the given entity, when initialized with an object +/// created for that initialization, requires destruction. +static bool shouldDestroyTemporary(const InitializedEntity &Entity) { + switch (Entity.getKind()) { + case InitializedEntity::EK_Member: + case InitializedEntity::EK_Result: + case InitializedEntity::EK_New: + case InitializedEntity::EK_Base: + case InitializedEntity::EK_VectorElement: + return false; + + case InitializedEntity::EK_Variable: + case InitializedEntity::EK_Parameter: + case InitializedEntity::EK_Temporary: + case InitializedEntity::EK_ArrayElement: + case InitializedEntity::EK_Exception: + return true; + } + + 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. @@ -3551,6 +3575,7 @@ InitializationSequence::Perform(Sema &S, bool IsCopy = false; FunctionDecl *Fn = Step->Function.Function; DeclAccessPair FoundFn = Step->Function.FoundDecl; + bool CreatedObject = false; bool IsLvalue = false; if (CXXConstructorDecl *Constructor = dyn_cast(Fn)) { // Build a call to the selected constructor. @@ -3581,6 +3606,8 @@ InitializationSequence::Perform(Sema &S, if (S.Context.hasSameUnqualifiedType(SourceType, Class) || S.IsDerivedFrom(SourceType, Class)) IsCopy = true; + + CreatedObject = true; } else { // Build a call to the conversion function. CXXConversionDecl *Conversion = cast(Fn); @@ -3606,23 +3633,37 @@ InitializationSequence::Perform(Sema &S, return S.ExprError(); CastKind = CastExpr::CK_UserDefinedConversion; + + CreatedObject = Conversion->getResultType()->isRecordType(); } bool RequiresCopy = !IsCopy && getKind() != InitializationSequence::ReferenceBinding; if (RequiresCopy || shouldBindAsTemporary(Entity)) CurInit = S.MaybeBindToTemporary(CurInit.takeAs()); - + else if (CreatedObject && shouldDestroyTemporary(Entity)) { + CurInitExpr = static_cast(CurInit.get()); + QualType T = CurInitExpr->getType(); + if (const RecordType *Record = T->getAs()) { + CXXDestructorDecl *Destructor + = cast(Record->getDecl())->getDestructor(S.Context); + S.CheckDestructorAccess(CurInitExpr->getLocStart(), Destructor, + S.PDiag(diag::err_access_dtor_temp) << T); + S.MarkDeclarationReferenced(CurInitExpr->getLocStart(), Destructor); + } + } + CurInitExpr = CurInit.takeAs(); CurInit = S.Owned(new (S.Context) ImplicitCastExpr(CurInitExpr->getType(), - CastKind, - CurInitExpr, + CastKind, + CurInitExpr, CXXBaseSpecifierArray(), - IsLvalue)); + IsLvalue)); if (RequiresCopy) CurInit = CopyObject(S, Entity.getType().getNonReferenceType(), Entity, move(CurInit), /*IsExtraneousCopy=*/false); + break; } @@ -3705,7 +3746,7 @@ InitializationSequence::Perform(Sema &S, if (shouldBindAsTemporary(Entity)) CurInit = S.MaybeBindToTemporary(CurInit.takeAs()); - + break; } diff --git a/clang/test/CXX/class.access/p4.cpp b/clang/test/CXX/class.access/p4.cpp index fdde73506220..2786aefa2814 100644 --- a/clang/test/CXX/class.access/p4.cpp +++ b/clang/test/CXX/class.access/p4.cpp @@ -349,4 +349,17 @@ namespace test14 { void test() { foo(); // expected-error {{temporary of type 'test14::A' has private destructor}} } + + class X { + ~X(); // expected-note {{declared private here}} + }; + + struct Y1 { + operator X(); + }; + + void g() { + const X &xr = Y1(); // expected-error{{temporary of type 'test14::X' has private destructor}} + } } +