From: Richard Smith Date: Sat, 3 Dec 2016 00:29:06 +0000 (+0000) Subject: PR31244: Use the exception specification from the callee's type directly to X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=431cab408b396f55b773d8896951c9f718558403;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@288558 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index e95482679b..3561bd02b9 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -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(D); - if (!VD) { - // In C++17, we may have a canonical exception specification. If so, use it. - if (auto *FT = E->getType().getCanonicalType()->getAs()) - 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(D) && D->hasAttr()) + if (D && isa(D) && D->hasAttr()) 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(E)) { + E = cast(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(E)) { + assert(Op->getOpcode() == BO_PtrMemD || Op->getOpcode() == BO_PtrMemI); + T = Op->getRHS()->getType() + ->castAs()->getPointeeType(); + } else { + T = cast(E)->getMemberDecl()->getType(); + } + } + } else if (const ValueDecl *VD = dyn_cast_or_null(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())) { } else if (const PointerType *PT = T->getAs()) @@ -1053,10 +1066,8 @@ CanThrowResult Sema::canThrow(const Expr *E) { CT = CT_Dependent; else if (isa(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)); diff --git a/test/SemaCXX/cxx1z-noexcept-function-type.cpp b/test/SemaCXX/cxx1z-noexcept-function-type.cpp index 0b22e3c86d..979a287906 100644 --- a/test/SemaCXX/cxx1z-noexcept-function-type.cpp +++ b/test/SemaCXX/cxx1z-noexcept-function-type.cpp @@ -30,6 +30,21 @@ auto deduce_auto_from_noexcept_function_ptr_b = redecl4; 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(init_with_exact_type_b)(0))); // expected-error {{is not allowed}} +static_assert(noexcept(reinterpret_cast(init_with_exact_type_b)(0))); +static_assert(!noexcept(static_cast(init_with_exact_type_a)(0))); + +template auto get_fn() noexcept -> void (*)() noexcept(B) {} +static_assert(noexcept(get_fn()())); +static_assert(!noexcept(get_fn()())); + namespace DependentDefaultCtorExceptionSpec { template struct T { static const bool value = true; };