Author: rsmith Date: Fri Dec 2 18:29:06 2016 New Revision: 288558 URL: http://llvm.org/viewvc/llvm-project?rev=288558&view=rev Log: 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.
Modified: cfe/trunk/lib/Sema/SemaExceptionSpec.cpp cfe/trunk/test/SemaCXX/cxx1z-noexcept-function-type.cpp Modified: cfe/trunk/lib/Sema/SemaExceptionSpec.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExceptionSpec.cpp?rev=288558&r1=288557&r2=288558&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExceptionSpec.cpp (original) +++ cfe/trunk/lib/Sema/SemaExceptionSpec.cpp Fri Dec 2 18:29:06 2016 @@ -944,24 +944,37 @@ static CanThrowResult canSubExprsThrow(S } 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 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)); Modified: cfe/trunk/test/SemaCXX/cxx1z-noexcept-function-type.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1z-noexcept-function-type.cpp?rev=288558&r1=288557&r2=288558&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/cxx1z-noexcept-function-type.cpp (original) +++ cfe/trunk/test/SemaCXX/cxx1z-noexcept-function-type.cpp Fri Dec 2 18:29:06 2016 @@ -30,6 +30,21 @@ auto deduce_auto_from_noexcept_function_ 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; }; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits