PR9882: Fix noexcept to deal with dependent new, delete, calls, and

dynamic_cast correctly.

llvm-svn: 131177
This commit is contained in:
Eli Friedman 2011-05-11 05:22:44 +00:00
parent 2a09d65979
commit c6587cc550
2 changed files with 34 additions and 17 deletions

View File

@ -1693,6 +1693,9 @@ static Expr::CanThrowResult CanDynamicCastThrow(const CXXDynamicCastExpr *DC) {
if (!DC->getTypeAsWritten()->isReferenceType())
return Expr::CT_Cannot;
if (DC->getSubExpr()->isTypeDependent())
return Expr::CT_Dependent;
return DC->getCastKind() == clang::CK_Dynamic? Expr::CT_Can : Expr::CT_Cannot;
}
@ -1747,7 +1750,11 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
case CallExprClass:
case CXXOperatorCallExprClass:
case CXXMemberCallExprClass: {
CanThrowResult CT = CanCalleeThrow(C,cast<CallExpr>(this)->getCalleeDecl());
CanThrowResult CT;
if (isTypeDependent())
CT = CT_Dependent;
else
CT = CanCalleeThrow(C, cast<CallExpr>(this)->getCalleeDecl());
if (CT == CT_Can)
return CT;
return MergeCanThrow(CT, CanSubExprsThrow(C, this));
@ -1763,7 +1770,11 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
}
case CXXNewExprClass: {
CanThrowResult CT = MergeCanThrow(
CanThrowResult CT;
if (isTypeDependent())
CT = CT_Dependent;
else
CT = MergeCanThrow(
CanCalleeThrow(C, cast<CXXNewExpr>(this)->getOperatorNew()),
CanCalleeThrow(C, cast<CXXNewExpr>(this)->getConstructor(),
/*NullThrows*/false));
@ -1773,22 +1784,18 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
}
case CXXDeleteExprClass: {
CanThrowResult CT = CanCalleeThrow(C,
cast<CXXDeleteExpr>(this)->getOperatorDelete());
if (CT == CT_Can)
return CT;
const Expr *Arg = cast<CXXDeleteExpr>(this)->getArgument();
// Unwrap exactly one implicit cast, which converts all pointers to void*.
if (const ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg))
Arg = Cast->getSubExpr();
if (const PointerType *PT = Arg->getType()->getAs<PointerType>()) {
if (const RecordType *RT = PT->getPointeeType()->getAs<RecordType>()) {
CanThrowResult CT2 = CanCalleeThrow(C,
cast<CXXRecordDecl>(RT->getDecl())->getDestructor());
if (CT2 == CT_Can)
return CT2;
CT = MergeCanThrow(CT, CT2);
CanThrowResult CT;
QualType DTy = cast<CXXDeleteExpr>(this)->getDestroyedType();
if (DTy.isNull() || DTy->isDependentType()) {
CT = CT_Dependent;
} else {
CT = CanCalleeThrow(C, cast<CXXDeleteExpr>(this)->getOperatorDelete());
if (const RecordType *RT = DTy->getAs<RecordType>()) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
CT = MergeCanThrow(CT, CanCalleeThrow(C, RD->getDestructor()));
}
if (CT == CT_Can)
return CT;
}
return MergeCanThrow(CT, CanSubExprsThrow(C, this));
}

View File

@ -155,12 +155,16 @@ void gencon() {
N(G3());
}
template <class T> void f(T&&) noexcept;
template <typename T, bool b>
void late() {
B(b, typeid(*(T*)0));
B(b, T(1));
B(b, static_cast<T>(S2(0, 0)));
B(b, S1() + T());
P(f(T()));
P(new (0) T);
P(delete (T*)0);
}
struct S3 {
virtual ~S3() throw();
@ -168,9 +172,15 @@ struct S3 {
explicit S3(int);
S3(const S2&);
};
template <class T> T&& f2() noexcept;
template <typename T>
void late2() {
P(dynamic_cast<S3&>(f2<T&>()));
}
void operator +(const S1&, float) throw();
void operator +(const S1&, const S3&);
void tlate() {
late<float, true>();
late<S3, false>();
late2<S3>();
}