forked from OSchip/llvm-project
PR31244: Use the exception specification from the callee's type directly to
compute whether a call is noexcept, even if we can't map the callee expression to a called declaration. llvm-svn: 288558
This commit is contained in:
parent
465bd0fc00
commit
3a8f13ac23
|
@ -944,24 +944,37 @@ static CanThrowResult canSubExprsThrow(Sema &S, const Expr *E) {
|
|||
}
|
||||
|
||||
static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D) {
|
||||
assert(D && "Expected decl");
|
||||
|
||||
// See if we can get a function type from the decl somehow.
|
||||
const ValueDecl *VD = dyn_cast<ValueDecl>(D);
|
||||
if (!VD) {
|
||||
// In C++17, we may have a canonical exception specification. If so, use it.
|
||||
if (auto *FT = E->getType().getCanonicalType()->getAs<FunctionProtoType>())
|
||||
return FT->isNothrow(S.Context) ? CT_Cannot : CT_Can;
|
||||
// If we have no clue what we're calling, assume the worst.
|
||||
return CT_Can;
|
||||
}
|
||||
|
||||
// As an extension, we assume that __attribute__((nothrow)) functions don't
|
||||
// throw.
|
||||
if (isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>())
|
||||
if (D && isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>())
|
||||
return CT_Cannot;
|
||||
|
||||
QualType T = VD->getType();
|
||||
QualType T;
|
||||
|
||||
// In C++1z, just look at the function type of the callee.
|
||||
if (S.getLangOpts().CPlusPlus1z && isa<CallExpr>(E)) {
|
||||
E = cast<CallExpr>(E)->getCallee();
|
||||
T = E->getType();
|
||||
if (T->isSpecificPlaceholderType(BuiltinType::BoundMember)) {
|
||||
// Sadly we don't preserve the actual type as part of the "bound member"
|
||||
// placeholder, so we need to reconstruct it.
|
||||
E = E->IgnoreParenImpCasts();
|
||||
|
||||
// Could be a call to a pointer-to-member or a plain member access.
|
||||
if (auto *Op = dyn_cast<BinaryOperator>(E)) {
|
||||
assert(Op->getOpcode() == BO_PtrMemD || Op->getOpcode() == BO_PtrMemI);
|
||||
T = Op->getRHS()->getType()
|
||||
->castAs<MemberPointerType>()->getPointeeType();
|
||||
} else {
|
||||
T = cast<MemberExpr>(E)->getMemberDecl()->getType();
|
||||
}
|
||||
}
|
||||
} else if (const ValueDecl *VD = dyn_cast_or_null<ValueDecl>(D))
|
||||
T = VD->getType();
|
||||
else
|
||||
// If we have no clue what we're calling, assume the worst.
|
||||
return CT_Can;
|
||||
|
||||
const FunctionProtoType *FT;
|
||||
if ((FT = T->getAs<FunctionProtoType>())) {
|
||||
} else if (const PointerType *PT = T->getAs<PointerType>())
|
||||
|
@ -1053,10 +1066,8 @@ CanThrowResult Sema::canThrow(const Expr *E) {
|
|||
CT = CT_Dependent;
|
||||
else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens()))
|
||||
CT = CT_Cannot;
|
||||
else if (CE->getCalleeDecl())
|
||||
CT = canCalleeThrow(*this, E, CE->getCalleeDecl());
|
||||
else
|
||||
CT = CT_Can;
|
||||
CT = canCalleeThrow(*this, E, CE->getCalleeDecl());
|
||||
if (CT == CT_Can)
|
||||
return CT;
|
||||
return mergeCanThrow(CT, canSubExprsThrow(*this, E));
|
||||
|
|
|
@ -30,6 +30,21 @@ auto deduce_auto_from_noexcept_function_ptr_b = redecl4<false>;
|
|||
using DeducedType_b = decltype(deduce_auto_from_noexcept_function_ptr_b);
|
||||
using DeducedType_b = void (*)(int);
|
||||
|
||||
static_assert(noexcept(init_with_exact_type_a(0)));
|
||||
static_assert(noexcept((+init_with_exact_type_a)(0)));
|
||||
static_assert(!noexcept(init_with_exact_type_b(0)));
|
||||
static_assert(!noexcept((+init_with_exact_type_b)(0)));
|
||||
|
||||
// Don't look through casts, use the direct type of the expression.
|
||||
// FIXME: static_cast here would be reasonable, but is not currently permitted.
|
||||
static_assert(noexcept(static_cast<decltype(init_with_exact_type_a)>(init_with_exact_type_b)(0))); // expected-error {{is not allowed}}
|
||||
static_assert(noexcept(reinterpret_cast<decltype(init_with_exact_type_a)>(init_with_exact_type_b)(0)));
|
||||
static_assert(!noexcept(static_cast<decltype(init_with_exact_type_b)>(init_with_exact_type_a)(0)));
|
||||
|
||||
template<bool B> auto get_fn() noexcept -> void (*)() noexcept(B) {}
|
||||
static_assert(noexcept(get_fn<true>()()));
|
||||
static_assert(!noexcept(get_fn<false>()()));
|
||||
|
||||
namespace DependentDefaultCtorExceptionSpec {
|
||||
template<typename> struct T { static const bool value = true; };
|
||||
|
||||
|
|
Loading…
Reference in New Issue