From: Douglas Gregor Date: Sat, 24 Apr 2010 23:45:46 +0000 (+0000) Subject: When we create a temporary of class type that we don't immediately X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4154e0b1a5d03cbe4836e381c7d6187b7a0a200c;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@102287 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index ea430bbd3e..e1269a7e12 100644 --- a/lib/Sema/SemaInit.cpp +++ b/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/test/CXX/class.access/p4.cpp b/test/CXX/class.access/p4.cpp index fdde735062..2786aefa28 100644 --- a/test/CXX/class.access/p4.cpp +++ b/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}} + } } +