r288558 - PR31244: Use the exception specification from the callee's type directly to

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Fri Dec 2 16:29:06 PST 2016


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; };
 




More information about the cfe-commits mailing list