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
This commit is contained in:
Douglas Gregor 2010-04-24 23:45:46 +00:00
parent dde8b46e62
commit 9556257252
2 changed files with 59 additions and 5 deletions

View File

@ -3138,6 +3138,8 @@ getAssignmentAction(const InitializedEntity &Entity) {
return Sema::AA_Converting; 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) { static bool shouldBindAsTemporary(const InitializedEntity &Entity) {
switch (Entity.getKind()) { switch (Entity.getKind()) {
case InitializedEntity::EK_ArrayElement: case InitializedEntity::EK_ArrayElement:
@ -3158,6 +3160,28 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) {
llvm_unreachable("missed an InitializedEntity kind?"); 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 /// \brief Make a (potentially elidable) temporary copy of the object
/// provided by the given initializer by calling the appropriate copy /// provided by the given initializer by calling the appropriate copy
/// constructor. /// constructor.
@ -3551,6 +3575,7 @@ InitializationSequence::Perform(Sema &S,
bool IsCopy = false; bool IsCopy = false;
FunctionDecl *Fn = Step->Function.Function; FunctionDecl *Fn = Step->Function.Function;
DeclAccessPair FoundFn = Step->Function.FoundDecl; DeclAccessPair FoundFn = Step->Function.FoundDecl;
bool CreatedObject = false;
bool IsLvalue = false; bool IsLvalue = false;
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Fn)) { if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Fn)) {
// Build a call to the selected constructor. // Build a call to the selected constructor.
@ -3581,6 +3606,8 @@ InitializationSequence::Perform(Sema &S,
if (S.Context.hasSameUnqualifiedType(SourceType, Class) || if (S.Context.hasSameUnqualifiedType(SourceType, Class) ||
S.IsDerivedFrom(SourceType, Class)) S.IsDerivedFrom(SourceType, Class))
IsCopy = true; IsCopy = true;
CreatedObject = true;
} else { } else {
// Build a call to the conversion function. // Build a call to the conversion function.
CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Fn); CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Fn);
@ -3606,23 +3633,37 @@ InitializationSequence::Perform(Sema &S,
return S.ExprError(); return S.ExprError();
CastKind = CastExpr::CK_UserDefinedConversion; CastKind = CastExpr::CK_UserDefinedConversion;
CreatedObject = Conversion->getResultType()->isRecordType();
} }
bool RequiresCopy = !IsCopy && bool RequiresCopy = !IsCopy &&
getKind() != InitializationSequence::ReferenceBinding; getKind() != InitializationSequence::ReferenceBinding;
if (RequiresCopy || shouldBindAsTemporary(Entity)) if (RequiresCopy || shouldBindAsTemporary(Entity))
CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
else if (CreatedObject && shouldDestroyTemporary(Entity)) {
CurInitExpr = static_cast<Expr *>(CurInit.get());
QualType T = CurInitExpr->getType();
if (const RecordType *Record = T->getAs<RecordType>()) {
CXXDestructorDecl *Destructor
= cast<CXXRecordDecl>(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<Expr>(); CurInitExpr = CurInit.takeAs<Expr>();
CurInit = S.Owned(new (S.Context) ImplicitCastExpr(CurInitExpr->getType(), CurInit = S.Owned(new (S.Context) ImplicitCastExpr(CurInitExpr->getType(),
CastKind, CastKind,
CurInitExpr, CurInitExpr,
CXXBaseSpecifierArray(), CXXBaseSpecifierArray(),
IsLvalue)); IsLvalue));
if (RequiresCopy) if (RequiresCopy)
CurInit = CopyObject(S, Entity.getType().getNonReferenceType(), Entity, CurInit = CopyObject(S, Entity.getType().getNonReferenceType(), Entity,
move(CurInit), /*IsExtraneousCopy=*/false); move(CurInit), /*IsExtraneousCopy=*/false);
break; break;
} }
@ -3705,7 +3746,7 @@ InitializationSequence::Perform(Sema &S,
if (shouldBindAsTemporary(Entity)) if (shouldBindAsTemporary(Entity))
CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>());
break; break;
} }

View File

@ -349,4 +349,17 @@ namespace test14 {
void test() { void test() {
foo(); // expected-error {{temporary of type 'test14::A' has private destructor}} 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}}
}
} }